/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 80017
 Source Host           : localhost:3306
 Source Schema         : markdoc_dev

 Target Server Type    : MySQL
 Target Server Version : 80017
 File Encoding         : 65001

 Date: 02/03/2020 21:31:11
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_codes
-- ----------------------------
DROP TABLE IF EXISTS `t_codes`;
CREATE TABLE `t_codes` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `code` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `expireAt` datetime DEFAULT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_codes
-- ----------------------------
BEGIN;
INSERT INTO `t_codes` VALUES (1, '576877', '1752295326@qq.com', '2020-02-17 15:39:06', 1, '2020-02-17 15:38:06');
INSERT INTO `t_codes` VALUES (2, '134944', '1752295326@qq.com', '2020-02-17 15:39:11', 1, '2020-02-17 15:38:10');
INSERT INTO `t_codes` VALUES (3, '008442', '1752295326@qq.com', '2020-02-17 15:52:02', 0, '2020-02-17 15:51:02');
INSERT INTO `t_codes` VALUES (4, '732355', '1752295326@qq.com', '2020-02-17 15:52:06', 0, '2020-02-17 15:51:05');
INSERT INTO `t_codes` VALUES (5, '084776', '1752295326@qq.com', '2020-02-17 15:52:07', 0, '2020-02-17 15:51:06');
INSERT INTO `t_codes` VALUES (6, '168963', '1752295326@qq.com', '2020-02-17 15:52:08', 0, '2020-02-17 15:51:08');
INSERT INTO `t_codes` VALUES (7, '213100', '1752295326@qq.com', '2020-02-17 15:52:10', 0, '2020-02-17 15:51:09');
INSERT INTO `t_codes` VALUES (8, '057082', '1752295326@qq.com', '2020-02-17 15:52:11', 0, '2020-02-17 15:51:10');
INSERT INTO `t_codes` VALUES (9, '647318', '1752295326@qq.com', '2020-02-17 15:52:19', 0, '2020-02-17 15:51:18');
INSERT INTO `t_codes` VALUES (10, '472423', '1752295326@qq.com', '2020-02-17 15:52:20', 0, '2020-02-17 15:51:19');
INSERT INTO `t_codes` VALUES (11, '287069', '1752295326@qq.com', '2020-02-17 15:52:20', 0, '2020-02-17 15:51:20');
INSERT INTO `t_codes` VALUES (12, '008554', '1752295326@qq.com', '2020-02-17 16:07:05', 1, '2020-02-17 16:06:05');
INSERT INTO `t_codes` VALUES (13, '606248', '1752295326@qq.com', '2020-02-17 16:09:23', 1, '2020-02-17 16:08:22');
INSERT INTO `t_codes` VALUES (14, '645579', '1752295326@qq.com', '2020-02-17 16:09:44', 1, '2020-02-17 16:08:44');
INSERT INTO `t_codes` VALUES (15, '457748', '1752295326@qq.com', '2020-02-17 16:10:26', 1, '2020-02-17 16:09:25');
INSERT INTO `t_codes` VALUES (16, '489929', 'lanyueos@qq.com', '2020-02-17 16:11:54', 1, '2020-02-17 16:10:54');
INSERT INTO `t_codes` VALUES (17, '607282', 'lanyueos@qq.com', '2020-02-17 17:47:20', 1, '2020-02-17 17:46:19');
INSERT INTO `t_codes` VALUES (18, '705383', 'lanyueos@qq.com', '2020-02-21 15:41:06', 0, '2020-02-21 15:40:05');
INSERT INTO `t_codes` VALUES (19, '569355', 'lanyueos@qq.com', '2020-02-21 15:43:38', 0, '2020-02-21 15:42:37');
COMMIT;

-- ----------------------------
-- Table structure for t_doc_tocs
-- ----------------------------
DROP TABLE IF EXISTS `t_doc_tocs`;
CREATE TABLE `t_doc_tocs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `parentId` int(11) DEFAULT NULL,
  `title` varchar(50) NOT NULL,
  `sort` int(255) NOT NULL DEFAULT '0',
  `docId` int(11) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `userId` int(11) DEFAULT NULL,
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_doc_tocs
-- ----------------------------
BEGIN;
INSERT INTO `t_doc_tocs` VALUES (1, NULL, '第一章第一节', 0, 1, 1, NULL, '2020-02-19 14:22:26', '2020-02-19 14:22:26');
INSERT INTO `t_doc_tocs` VALUES (2, NULL, '第一章第一节', 2, 1, 1, NULL, '2020-02-19 14:23:37', '2020-02-19 14:23:37');
INSERT INTO `t_doc_tocs` VALUES (3, NULL, '第一章第一节', 2, 1, 1, NULL, '2020-02-19 14:23:37', '2020-02-19 14:23:37');
INSERT INTO `t_doc_tocs` VALUES (4, NULL, '第一章第一节', 2, 1, 1, NULL, '2020-02-19 14:23:38', '2020-02-19 14:23:38');
INSERT INTO `t_doc_tocs` VALUES (6, NULL, '第一章第一节', 2, 1, 1, NULL, '2020-02-19 14:23:39', '2020-02-19 14:23:39');
INSERT INTO `t_doc_tocs` VALUES (8, NULL, '入门介绍', 2, 1, 1, NULL, '2020-02-19 14:24:47', '2020-02-19 14:24:47');
INSERT INTO `t_doc_tocs` VALUES (9, NULL, '高级语法', 2, 1, 1, NULL, '2020-02-19 14:24:56', '2020-02-19 14:24:56');
INSERT INTO `t_doc_tocs` VALUES (10, NULL, '高级语法', 2, 1, 1, NULL, '2020-02-19 14:27:02', '2020-02-19 14:27:02');
INSERT INTO `t_doc_tocs` VALUES (11, NULL, '测试用例', 10, 1, 1, 8, '2020-02-19 14:28:12', '2020-02-19 14:30:43');
INSERT INTO `t_doc_tocs` VALUES (12, 1, '扩展阅读', 2, 1, 1, 8, '2020-02-19 14:57:35', '2020-02-19 14:57:35');
INSERT INTO `t_doc_tocs` VALUES (13, 1, '扩展阅读', 2, 1, 1, 8, '2020-02-19 15:13:14', '2020-02-19 15:13:14');
COMMIT;

-- ----------------------------
-- Table structure for t_docs
-- ----------------------------
DROP TABLE IF EXISTS `t_docs`;
CREATE TABLE `t_docs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(50) NOT NULL,
  `description` varchar(300) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `viewType` varchar(15) DEFAULT 'public',
  `userId` int(11) DEFAULT NULL COMMENT '创建人',
  `sort` int(11) NOT NULL DEFAULT '0',
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_docs
-- ----------------------------
BEGIN;
INSERT INTO `t_docs` VALUES (1, 'Hello world !', '大多数 React 应用都会使用 Webpack，Rollup 或 Browserify 这类的构建工具来打包文件。 打包是一个将文件引入并合并到一个单独文件的过程，最终形成一个 “bundle”。 接着在页面上引入该 bundle，整个应用即可一次性加载。\n\n', 1, 'public', NULL, 0, '2020-02-19 11:21:37', '2020-02-27 11:26:35');
INSERT INTO `t_docs` VALUES (2, 'Markdoc 文档', '所有文档', 1, 'test', NULL, 0, '2020-02-19 11:21:55', '2020-02-20 17:35:14');
INSERT INTO `t_docs` VALUES (3, 'OAuth 2.0 文档', '测试文档描述', 1, 'test', 8, 1, '2020-02-19 11:24:00', '2020-02-20 17:36:00');
INSERT INTO `t_docs` VALUES (12, 'Github 使用文档', '测试', 1, 'public', 9, 0, '2020-02-21 16:08:11', '2020-02-21 16:08:11');
INSERT INTO `t_docs` VALUES (13, 'React 使用指南', 'React docs', 1, 'public', 9, 0, '2020-02-21 16:09:45', '2020-02-21 16:09:45');
INSERT INTO `t_docs` VALUES (14, 'Vue 文档', 'Vue 入门介绍', 1, 'public', 9, 0, '2020-02-21 16:11:48', '2020-02-21 16:11:48');
INSERT INTO `t_docs` VALUES (15, 'werwer', 'aserqwer', 1, 'public', 9, 0, '2020-02-21 16:13:09', '2020-02-21 16:13:09');
INSERT INTO `t_docs` VALUES (16, 'asdasdasdasd', 'asdfasdf', 1, 'public', 9, 0, '2020-02-21 16:56:01', '2020-02-21 16:56:01');
INSERT INTO `t_docs` VALUES (17, 'asdfasdf', 'asdfadf', 1, 'public', 9, 0, '2020-02-21 19:12:43', '2020-02-21 19:12:43');
COMMIT;

-- ----------------------------
-- Table structure for t_posts
-- ----------------------------
DROP TABLE IF EXISTS `t_posts`;
CREATE TABLE `t_posts` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `userId` int(11) DEFAULT NULL,
  `tocId` int(11) DEFAULT NULL COMMENT '所属目录',
  `docId` int(11) DEFAULT NULL COMMENT '所属文档',
  `title` varchar(50) NOT NULL,
  `abstract` varchar(300) NOT NULL DEFAULT '',
  `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `contentType` varchar(10) DEFAULT 'md' COMMENT '内容类型，html,md',
  `viewCount` int(11) NOT NULL DEFAULT '0',
  `tags` varchar(255) NOT NULL DEFAULT '' COMMENT '标签，多个逗号分隔',
  `status` tinyint(4) DEFAULT '1',
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_posts
-- ----------------------------
BEGIN;
INSERT INTO `t_posts` VALUES (1, 8, 1, 1, '文章标题', '', '# Hi !', 'md', 19, 'test,dev', 1, '2020-02-19 15:58:52', '2020-02-26 16:20:02');
INSERT INTO `t_posts` VALUES (2, 8, 13, 1, '文章标题', '', '\n# vue-dotmd-loader\n\nA webpack loader for loader markdown file transform to vue file.\n\n\n[中文](./README-zh.md)\n\n**Features**：\n\n+ [x] Support to import Vue file components and render them into Vue component instances\n+ [x] Code block supports highlighting specified lines\n+ [x] Supports writing Vue code and defining `script` to render to the current component\n+ [x] Support defining current component style\n+ [x] Support todolist\n+ [x] Support code block rendering components (requires the `ESM` version of Vue)\n+ [x] Support for importing file code (rendering to code highlight)\n+ [x] Support to import source code (such as importing HTML fragments, note: it will not be compiled through markdown)\n\n\nDetailed usage：[Docs](https://mengdu.github.io/vue-dotmd-loader/index.html)\n\n## Usage\n\n**install**\n\n```ls\nnpm install -D vue-dotmd-loader\n```\n\n**webpack.config.js**\n\n```js\n{\n  rules: [\n    {\n      test: /\\.md$/,\n      use: [\n        \'vue-loader\', // must use vue-loader\n        {\n          loader: \'vue-dotmd-loader\',\n          options: options\n        }\n      ]\n    }\n  ]\n}\n```\n\n**options**：\n\n```js\n{\n  wrapperName: \'DemoBlock\', // Define the demo package component (please register the component globally). If it is empty, only the demo will be rendered.\n  fileDemoNamePerfix: \'FileDemo\', // Name prefix of the demo component file\n  blockDemoNamePerfix: \'BlockCodeDemo\',// Name prefix of Code block demo component\n  fileDemoTag: \'demo:vue\', // File demo tag; format: [demo:vue](filePath)\n  blockDemoTag: \'demo:vue\', // Block code demo tag; format: ````html demo:vue code ````\n  includeCodeTag: \'include:code\', // Include code tag; format: [include:code](filePath)\n  includeRawTag: \'include:raw\', // Include raw source tag; format: [include:raw](filePath)\n  dest: false, // ouput file; true/false/function\n  dest (code, contextPath, resourcePath) {}, // Custom write file\n  markdown: { // markdown-it options see: https://github.com/markdown-it/markdown-it#init-with-presets-and-options\n    options: {\n      html: false\n    },\n    notWrapper: false,\n    init (md) {\n      md.use(otherPlugin) // Add markdown-it plug-in\n    }\n  }\n}\n```\n\n**eslint ignore**\n\n```json\n{\n  \"eslintIgnore\": [\n    \"**/*.md\"\n  ]\n}\n```\n\nIf you need the same style as this page, please refer to CSS as follows.\n\n```js\nimport \'github-markdown-css/github-markdown.css\'\nimport \'highlight.js/styles/color-brewer.css\'\nimport \'vue-dotmd-loader/src/docs.css\'\n```\n\n## Vue CLI\n\nIf you are using a project initialized by Vue cli, configure it as follows.\n\n```js\n{\n  // ...\n  configureWebpack: {\n    resolve: {\n      extensions: [\'.md\'],\n    }\n  },\n  chainWebpack (config) {\n    // see: https://github.com/neutrinojs/webpack-chain\n    config.module\n      .rule(\'dotmd\')\n      .test(/\\.md$/)\n      .use(\'vue-loader\')\n      .loader(\'vue-loader\')\n      .options({\n        ...(config.module.rules.get(\'vue\').uses.get(\'vue-loader\').get(\'options\') || null) // Consistent with Vue loader configuration\n      })\n      .end()\n      .use(\'vue-dotmd-loader\')\n      .loader(\'vue-dotmd-loader\')\n      .options({\n        dest: true,\n        markdown: {\n          options: {\n            html: true\n          }\n        }\n      })\n      .end()\n  }\n}\n```', 'md', 0, 'test,dev', 1, '2020-02-19 16:01:36', '2020-02-27 18:38:34');
INSERT INTO `t_posts` VALUES (3, 8, 8, 1, '代码分割', 'react', '---\nid: code-splitting\ntitle: 代码分割\npermalink: docs/code-splitting.html\n---\n\n## 打包 {#bundling}\n\n大多数 React 应用都会使用 [Webpack](https://webpack.docschina.org)，[Rollup](https://rollupjs.org/) 或 [Browserify](http://browserify.org/) 这类的构建工具来打包文件。\n打包是一个将文件引入并合并到一个单独文件的过程，最终形成一个 “bundle”。\n接着在页面上引入该 bundle，整个应用即可一次性加载。\n\n#### 示例 {#example}\n\n**App文件：**\n\n```js\n// app.js\nimport { add } from \'./math.js\';\n\nconsole.log(add(16, 26)); // 42\n```\n\n```js\n// math.js\nexport function add(a, b) {\n  return a + b;\n}\n```\n\n**打包后文件：**\n\n```js\nfunction add(a, b) {\n  return a + b;\n}\n\nconsole.log(add(16, 26)); // 42\n```\n\n> 注意：\n>\n> 最终你的打包文件看起来会和上面的例子区别很大。\n\n如果你正在使用 [Create React App](https://github.com/facebookincubator/create-react-app)，[Next.js](https://github.com/zeit/next.js/)，[Gatsby](https://www.gatsbyjs.org/)，或者类似的工具，你会拥有一个可以直接使用的 Webpack 配置来进行打包工作。\n\n如果你没有使用这类工具，你就需要自己来进行配置。例如，查看 Webpack 文档上的[安装](https://webpack.docschina.org/guides/installation/)和[入门教程](https://webpack.docschina.org/guides/getting-started/)。\n\n## 代码分割 {#code-splitting}\n\n打包是个非常棒的技术，但随着你的应用增长，你的代码包也将随之增长。尤其是在整合了体积巨大的第三方库的情况下。你需要关注你代码包中所包含的代码，以避免因体积过大而导致加载时间过长。\n\n为了避免搞出大体积的代码包，在前期就思考该问题并对代码包进行分割是个不错的选择。\n代码分割是由诸如 [Webpack](https://webpack.docschina.org/guides/code-splitting/)，[Rollup](https://rollupjs.org/guide/en/#code-splitting) 和 Browserify（[factor-bundle](https://github.com/browserify/factor-bundle)）这类打包器支持的一项技术，能够创建多个包并在运行时动态加载。\n\n对你的应用进行代码分割能够帮助你“懒加载”当前用户所需要的内容，能够显著地提高你的应用性能。尽管并没有减少应用整体的代码体积，但你可以避免加载用户永远不需要的代码，并在初始加载的时候减少所需加载的代码量。\n\n## `import()` {#import}\n\n在你的应用中引入代码分割的最佳方式是通过动态 `import()` 语法。\n\n**使用之前：**\n\n```js\nimport { add } from \'./math\';\n\nconsole.log(add(16, 26));\n```\n\n**使用之后：**\n\n```js\nimport(\"./math\").then(math => {\n  console.log(math.add(16, 26));\n});\n```\n\n当 Webpack 解析到该语法时，会自动进行代码分割。如果你使用 Create React App，该功能已开箱即用，你可以[立刻使用](https://facebook.github.io/create-react-app/docs/code-splitting)该特性。[Next.js](https://github.com/zeit/next.js/#dynamic-import) 也已支持该特性而无需进行配置。\n\n如果你自己配置 Webpack，你可能要阅读下 Webpack 关于[代码分割](https://webpack.docschina.org/guides/code-splitting/)的指南。你的 Webpack 配置应该[类似于此](https://gist.github.com/gaearon/ca6e803f5c604d37468b0091d9959269)。\n\n当使用 [Babel](https://babel.docschina.org/) 时，你要确保 Babel 能够解析动态 import 语法而不是将其进行转换。对于这一要求你需要 [babel-plugin-syntax-dynamic-import](https://yarnpkg.com/en/package/babel-plugin-syntax-dynamic-import) 插件。\n\n## `React.lazy` {#reactlazy}\n\n> 注意:\n>\n> `React.lazy` 和 Suspense 技术还不支持服务端渲染。如果你想要在使用服务端渲染的应用中使用，我们推荐 [Loadable Components](https://github.com/gregberge/loadable-components) 这个库。它有一个很棒的[服务端渲染打包指南](https://loadable-components.com/docs/server-side-rendering/)。\n\n`React.lazy` 函数能让你像渲染常规组件一样处理动态引入（的组件）。\n\n**使用之前：**\n\n```js\nimport OtherComponent from \'./OtherComponent\';\n```\n\n**使用之后：**\n\n```js\nconst OtherComponent = React.lazy(() => import(\'./OtherComponent\'));\n```\n\n此代码将会在组件首次渲染时，自动导入包含 `OtherComponent` 组件的包。\n\n`React.lazy` 接受一个函数，这个函数需要动态调用 `import()`。它必须返回一个 `Promise`，该 Promise 需要 resolve 一个 `defalut` export 的 React 组件。\n\n然后应在 `Suspense` 组件中渲染 lazy 组件，如此使得我们可以使用在等待加载 lazy 组件时做优雅降级（如 loading 指示器等）。\n\n```js\nconst OtherComponent = React.lazy(() => import(\'./OtherComponent\'));\n\nfunction MyComponent() {\n  return (\n    <div>\n      <Suspense fallback={<div>Loading...</div>}>\n        <OtherComponent />\n      </Suspense>\n    </div>\n  );\n}\n```\n\n`fallback` 属性接受任何在组件加载过程中你想展示的 React 元素。你可以将 `Suspense` 组件置于懒加载组件之上的任何位置。你甚至可以用一个 `Suspense` 组件包裹多个懒加载组件。\n\n```js\nconst OtherComponent = React.lazy(() => import(\'./OtherComponent\'));\nconst AnotherComponent = React.lazy(() => import(\'./AnotherComponent\'));\n\nfunction MyComponent() {\n  return (\n    <div>\n      <Suspense fallback={<div>Loading...</div>}>\n        <section>\n          <OtherComponent />\n          <AnotherComponent />\n        </section>\n      </Suspense>\n    </div>\n  );\n}\n```\n\n### 异常捕获边界（Error boundaries）{#error-boundaries}\n\n如果模块加载失败（如网络问题），它会触发一个错误。你可以通过[异常捕获边界（Error boundaries）](/docs/error-boundaries.html)技术来处理这些情况，以显示良好的用户体验并管理恢复事宜。\n\n```js\nimport MyErrorBoundary from \'./MyErrorBoundary\';\nconst OtherComponent = React.lazy(() => import(\'./OtherComponent\'));\nconst AnotherComponent = React.lazy(() => import(\'./AnotherComponent\'));\n\nconst MyComponent = () => (\n  <div>\n    <MyErrorBoundary>\n      <Suspense fallback={<div>Loading...</div>}>\n        <section>\n          <OtherComponent />\n          <AnotherComponent />\n        </section>\n      </Suspense>\n    </MyErrorBoundary>\n  </div>\n);\n```\n\n## 基于路由的代码分割 {#route-based-code-splitting}\n\n决定在哪引入代码分割需要一些技巧。你需要确保选择的位置能够均匀地分割代码包而不会影响用户体验。\n\n一个不错的选择是从路由开始。大多数网络用户习惯于页面之间能有个加载切换过程。你也可以选择重新渲染整个页面，这样您的用户就不必在渲染的同时再和页面上的其他元素进行交互。\n\n这里是一个例子，展示如何在你的应用中使用 `React.lazy` 和 [React Router](https://react-router.docschina.org/) 这类的第三方库，来配置基于路由的代码分割。\n\n```js\nimport { BrowserRouter as Router, Route, Switch } from \'react-router-dom\';\nimport React, { Suspense, lazy } from \'react\';\n\nconst Home = lazy(() => import(\'./routes/Home\'));\nconst About = lazy(() => import(\'./routes/About\'));\n\nconst App = () => (\n  <Router>\n    <Suspense fallback={<div>Loading...</div>}>\n      <Switch>\n        <Route exact path=\"/\" component={Home}/>\n        <Route path=\"/about\" component={About}/>\n      </Switch>\n    </Suspense>\n  </Router>\n);\n```\n\n## 命名导出（Named Exports）{#named-exports}\n\n`React.lazy` 目前只支持默认导出（default exports）。如果你想被引入的模块使用命名导出（named exports），你可以创建一个中间模块，来重新导出为默认模块。这能保证 tree shaking 不会出错，并且不必引入不需要的组件。\n\n```js\n// ManyComponents.js\nexport const MyComponent = /* ... */;\nexport const MyUnusedComponent = /* ... */;\n```\n\n```js\n// MyComponent.js\nexport { MyComponent as default } from \"./ManyComponents.js\";\n```\n\n```js\n// MyApp.js\nimport React, { lazy } from \'react\';\nconst MyComponent = lazy(() => import(\"./MyComponent.js\"));\n```\n', 'md', 152, 'test,dev', 1, '2020-02-19 16:01:42', '2020-02-27 18:30:53');
INSERT INTO `t_posts` VALUES (4, 8, 9, 1, '测试文档', 'react', '---\nid: context\ntitle: Context\npermalink: docs/context.html\n---\n\nContext 提供了一个无需为每层组件手动添加 props，就能在组件树间进行数据传递的方法。\n\n在一个典型的 React 应用中，数据是通过 props 属性自上而下（由父及子）进行传递的，但这种做法对于某些类型的属性而言是极其繁琐的（例如：地区偏好，UI 主题），这些属性是应用程序中许多组件都需要的。Context 提供了一种在组件之间共享此类值的方式，而不必显式地通过组件树的逐层传递 props。\n\n- [何时使用 Context](#when-to-use-context)\n- [使用 Context 之前的考虑](#before-you-use-context)\n- [API](#api)\n  - [React.createContext](#reactcreatecontext)\n  - [Context.Provider](#contextprovider)\n  - [Class.contextType](#classcontexttype)\n  - [Context.Consumer](#contextconsumer)\n  - [Context.displayName](#contextdisplayname)\n- [示例](#examples)\n  - [动态 Context](#dynamic-context)\n  - [在嵌套组件中更新 Context](#updating-context-from-a-nested-component)\n  - [使用多个 Context](#consuming-multiple-contexts)\n- [注意事项](#caveats)\n- [废弃的 API](#legacy-api)\n\n## 何时使用 Context {#when-to-use-context}\n\nContext 设计目的是为了共享那些对于一个组件树而言是“全局”的数据，例如当前认证的用户、主题或首选语言。举个例子，在下面的代码中，我们通过一个 “theme” 属性手动调整一个按钮组件的样式：\n\n`embed:context/motivation-problem.js`\n\n使用 context, 我们可以避免通过中间元素传递 props：\n\n`embed:context/motivation-solution.js`\n\n## 使用 Context 之前的考虑 {#before-you-use-context}\n\nContext 主要应用场景在于*很多*不同层级的组件需要访问同样一些的数据。请谨慎使用，因为这会使得组件的复用性变差。\n\n**如果你只是想避免层层传递一些属性，[组件组合（component composition）](/docs/composition-vs-inheritance.html)有时候是一个比 context 更好的解决方案。**\n\n比如，考虑这样一个 `Page` 组件，它层层向下传递 `user` 和 `avatarSize` 属性，从而深度嵌套的 `Link` 和 `Avatar` 组件可以读取到这些属性：\n\n```js\n<Page user={user} avatarSize={avatarSize} />\n// ... 渲染出 ...\n<PageLayout user={user} avatarSize={avatarSize} />\n// ... 渲染出 ...\n<NavigationBar user={user} avatarSize={avatarSize} />\n// ... 渲染出 ...\n<Link href={user.permalink}>\n  <Avatar user={user} size={avatarSize} />\n</Link>\n```\n\n如果在最后只有 `Avatar` 组件真的需要 `user` 和 `avatarSize`，那么层层传递这两个 props 就显得非常冗余。而且一旦 `Avatar` 组件需要更多从来自顶层组件的 props，你还得在中间层级一个一个加上去，这将会变得非常麻烦。\n\n一种**无需 context** 的解决方案是[将 `Avatar` 组件自身传递下去](/docs/composition-vs-inheritance.html#containment)，因而中间组件无需知道 `user` 或者 `avatarSize` 等 props：\n\n```js\nfunction Page(props) {\n  const user = props.user;\n  const userLink = (\n    <Link href={user.permalink}>\n      <Avatar user={user} size={props.avatarSize} />\n    </Link>\n  );\n  return <PageLayout userLink={userLink} />;\n}\n\n// 现在，我们有这样的组件：\n<Page user={user} avatarSize={avatarSize} />\n// ... 渲染出 ...\n<PageLayout userLink={...} />\n// ... 渲染出 ...\n<NavigationBar userLink={...} />\n// ... 渲染出 ...\n{props.userLink}\n```\n\n这种变化下，只有最顶部的 Page 组件需要知道 `Link` 和 `Avatar` 组件是如何使用 `user` 和 `avatarSize` 的。\n\n这种对组件的*控制反转*减少了在你的应用中要传递的 props 数量，这在很多场景下会使得你的代码更加干净，使你对根组件有更多的把控。但是，这并不适用于每一个场景：这种将逻辑提升到组件树的更高层次来处理，会使得这些高层组件变得更复杂，并且会强行将低层组件适应这样的形式，这可能不会是你想要的。\n\n而且你的组件并不限制于接收单个子组件。你可能会传递多个子组件，甚至会为这些子组件（children）封装多个单独的“接口（slots）”，[正如这里的文档所列举的](/docs/composition-vs-inheritance.html#containment)\n\n```js\nfunction Page(props) {\n  const user = props.user;\n  const content = <Feed user={user} />;\n  const topBar = (\n    <NavigationBar>\n      <Link href={user.permalink}>\n        <Avatar user={user} size={props.avatarSize} />\n      </Link>\n    </NavigationBar>\n  );\n  return (\n    <PageLayout\n      topBar={topBar}\n      content={content}\n    />\n  );\n}\n```\n\n这种模式足够覆盖很多场景了，在这些场景下你需要将子组件和直接关联的父组件解耦。如果子组件需要在渲染前和父组件进行一些交流，你可以进一步使用 [render props](/docs/render-props.html)。\n\n但是，有的时候在组件树中很多不同层级的组件需要访问同样的一批数据。Context 能让你将这些数据向组件树下所有的组件进行“广播”，所有的组件都能访问到这些数据，也能访问到后续的数据更新。使用 context 的通用的场景包括管理当前的 locale，theme，或者一些缓存数据，这比替代方案要简单的多。\n\n## API {#api}\n\n### `React.createContext` {#reactcreatecontext}\n\n```js\nconst MyContext = React.createContext(defaultValue);\n```\n\n创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件，这个组件会从组件树中离自身最近的那个匹配的 `Provider` 中读取到当前的 context 值。\n\n**只有**当组件所处的树中没有匹配到 Provider 时，其 `defaultValue` 参数才会生效。这有助于在不使用 Provider 包装组件的情况下对组件进行测试。注意：将 `undefined` 传递给 Provider 的 value 时，消费组件的 `defaultValue` 不会生效。\n\n### `Context.Provider` {#contextprovider}\n\n```js\n<MyContext.Provider value={/* 某个值 */}>\n```\n\n每个 Context 对象都会返回一个 Provider React 组件，它允许消费组件订阅 context 的变化。\n\nProvider 接收一个 `value` 属性，传递给消费组件。一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使用，里层的会覆盖外层的数据。\n\n当 Provider 的 `value` 值发生变化时，它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不受制于 `shouldComponentUpdate` 函数，因此当 consumer 组件在其祖先组件退出更新的情况下也能更新。\n\n通过新旧值检测来确定变化，使用了与 [`Object.is`](//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description) 相同的算法。\n\n> 注意\n>\n> 当传递对象给 `value` 时，检测变化的方式会导致一些问题：详见[注意事项](#caveats)。\n\n### `Class.contextType` {#classcontexttype}\n\n```js\nclass MyClass extends React.Component {\n  componentDidMount() {\n    let value = this.context;\n    /* 在组件挂载完成后，使用 MyContext 组件的值来执行一些有副作用的操作 */\n  }\n  componentDidUpdate() {\n    let value = this.context;\n    /* ... */\n  }\n  componentWillUnmount() {\n    let value = this.context;\n    /* ... */\n  }\n  render() {\n    let value = this.context;\n    /* 基于 MyContext 组件的值进行渲染 */\n  }\n}\nMyClass.contextType = MyContext;\n```\n\n挂载在 class 上的 `contextType` 属性会被重赋值为一个由 [`React.createContext()`](#reactcreatecontext) 创建的 Context 对象。这能让你使用 `this.context` 来消费最近 Context 上的那个值。你可以在任何生命周期中访问到它，包括 render 函数中。\n\n> 注意：\n>\n> 你只通过该 API 订阅单一 context。如果你想订阅多个，阅读[使用多个 Context](#consuming-multiple-contexts) 章节\n>\n> 如果你正在使用实验性的 [public class fields 语法](https://babeljs.io/docs/plugins/transform-class-properties/)，你可以使用 `static` 这个类属性来初始化你的 `contextType`。\n\n\n```js\nclass MyClass extends React.Component {\n  static contextType = MyContext;\n  render() {\n    let value = this.context;\n    /* 基于这个值进行渲染工作 */\n  }\n}\n```\n\n### `Context.Consumer` {#contextconsumer}\n\n```js\n<MyContext.Consumer>\n  {value => /* 基于 context 值进行渲染*/}\n</MyContext.Consumer>\n```\n\n这里，React 组件也可以订阅到 context 变更。这能让你在[函数式组件](/docs/components-and-props.html#function-and-class-components)中完成订阅 context。\n\n这需要[函数作为子元素（function as a child）](/docs/render-props.html#using-props-other-than-render)这种做法。这个函数接收当前的 context 值，返回一个 React 节点。传递给函数的 `value` 值等同于往上组件树离这个 context 最近的 Provider 提供的 `value` 值。如果没有对应的 Provider，`value` 参数等同于传递给 `createContext()` 的 `defaultValue`。\n\n> 注意\n>\n> 想要了解更多关于 “函数作为子元素（function as a child）” 模式，详见 [render props](/docs/render-props.html)。\n\n### `Context.displayName` {#contextdisplayname}\n\ncontext 对象接受一个名为 `displayName` 的 property，类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。\n\n示例，下述组件在 DevTools 中将显示为 MyDisplayName：\n\n```js{2}\nconst MyContext = React.createContext(/* some value */);\nMyContext.displayName = \'MyDisplayName\';\n\n<MyContext.Provider> // \"MyDisplayName.Provider\" 在 DevTools 中\n<MyContext.Consumer> // \"MyDisplayName.Consumer\" 在 DevTools 中\n```\n\n## 示例 {#examples}\n\n### 动态 Context {#dynamic-context}\n\n对于上面的 theme 例子，使用动态值（dynamic values）后更复杂的用法：\n\n**theme-context.js**\n`embed:context/theme-detailed-theme-context.js`\n\n**themed-button.js**\n`embed:context/theme-detailed-themed-button.js`\n\n**app.js**\n`embed:context/theme-detailed-app.js`\n\n### 在嵌套组件中更新 Context {#updating-context-from-a-nested-component}\n\n从一个在组件树中嵌套很深的组件中更新 context 是很有必要的。在这种场景下，你可以通过 context 传递一个函数，使得 consumers 组件更新 context：\n\n**theme-context.js**\n`embed:context/updating-nested-context-context.js`\n\n**theme-toggler-button.js**\n`embed:context/updating-nested-context-theme-toggler-button.js`\n\n**app.js**\n`embed:context/updating-nested-context-app.js`\n\n### 消费多个 Context {#consuming-multiple-contexts}\n\n为了确保 context 快速进行重渲染，React 需要使每一个 consumers 组件的 context 在组件树中成为一个单独的节点。\n\n`embed:context/multiple-contexts.js`\n\n如果两个或者更多的 context 值经常被一起使用，那你可能要考虑一下另外创建你自己的渲染组件，以提供这些值。\n\n## 注意事项 {#caveats}\n\n因为 context 会使用参考标识（reference identity）来决定何时进行渲染，这里可能会有一些陷阱，当 provider 的父组件进行重渲染时，可能会在 consumers 组件中触发意外的渲染。举个例子，当每一次 Provider 重渲染时，以下的代码会重渲染所有下面的 consumers 组件，因为 `value` 属性总是被赋值为新的对象：\n\n`embed:context/reference-caveats-problem.js`\n\n为了防止这种情况，将 value 状态提升到父节点的 state 里：\n\n`embed:context/reference-caveats-solution.js`\n\n## 过时的 API {#legacy-api}\n\n> 注意\n>\n> 先前 React 使用实验性的 context API 运行，旧的 API 将会在所有 16.x 版本中得到支持，但用到它的应用应该迁移到新版本。过时的 API 将在未来的 React 版本中被移除。阅读[过时的 context 文档](/docs/legacy-context.html)了解更多。\n', 'md', 115, 'test,dev', 1, '2020-02-19 16:01:42', '2020-02-27 17:18:10');
COMMIT;

-- ----------------------------
-- Table structure for t_tokens
-- ----------------------------
DROP TABLE IF EXISTS `t_tokens`;
CREATE TABLE `t_tokens` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `userId` int(11) NOT NULL,
  `token` varchar(255) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `expireAt` datetime DEFAULT NULL,
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_tokens
-- ----------------------------
BEGIN;
INSERT INTO `t_tokens` VALUES (1, 1, '7aae8e22-da18-4063-bcc9-8838ca46abed', 1, '2020-03-15 12:47:32', '2020-02-14 12:47:32');
INSERT INTO `t_tokens` VALUES (2, 1, '7c8e9f37-1ee2-4797-b387-24a4699bbca9', 1, '2020-03-15 12:50:15', '2020-02-14 12:50:15');
INSERT INTO `t_tokens` VALUES (3, 1, 'a311db26-0461-4ce1-a1b8-8a36297dadbb', 1, '2020-03-15 14:20:43', '2020-02-14 14:20:43');
INSERT INTO `t_tokens` VALUES (4, 6, 'b5861836-c7a9-41b3-a87d-4ef7b811a333', 1, '2020-03-15 18:14:13', '2020-02-14 18:14:13');
INSERT INTO `t_tokens` VALUES (5, 6, 'ed49e4cb-c538-462f-9f1c-2edf5bba1bca', 1, '2020-03-15 18:14:16', '2020-02-14 18:14:16');
INSERT INTO `t_tokens` VALUES (6, 6, '9fa05bac-2a69-439d-ba01-c04a464e8f5c', 1, '2020-03-15 18:14:22', '2020-02-14 18:14:22');
INSERT INTO `t_tokens` VALUES (7, 6, '0e6621bf-e5fb-4dc4-84d8-9e930b1a6ea9', 1, '2020-03-15 18:14:23', '2020-02-14 18:14:23');
INSERT INTO `t_tokens` VALUES (8, 6, 'fa310c9f-4ca0-49ab-ae59-3eeb28949965', 1, '2020-03-15 18:14:24', '2020-02-14 18:14:24');
INSERT INTO `t_tokens` VALUES (9, 6, '1300ef96-533d-4cd2-965f-308d9e13693c', 1, '2020-03-15 18:14:25', '2020-02-14 18:14:25');
INSERT INTO `t_tokens` VALUES (10, 6, 'ea7d7012-4944-4ce4-83d7-9b0c73b13e2f', 1, '2020-03-15 18:14:26', '2020-02-14 18:14:26');
INSERT INTO `t_tokens` VALUES (11, 6, '614c2588-2dfe-4f84-99bc-5844bcc3585b', 1, '2020-03-15 18:14:27', '2020-02-14 18:14:27');
INSERT INTO `t_tokens` VALUES (12, 6, 'd07fe0d2-cf45-49ae-817c-26a8880c94c5', 1, '2020-02-13 18:14:28', '2020-02-14 18:14:28');
INSERT INTO `t_tokens` VALUES (13, 8, 'f2ed20e2-dabb-4781-a290-0dd41727f98d', 1, '2020-03-15 18:39:52', '2020-02-14 18:39:52');
INSERT INTO `t_tokens` VALUES (14, 8, 'ed20b6be-6011-4516-ba7c-5d3132365dca', 1, '2020-03-15 18:40:03', '2020-02-14 18:40:03');
INSERT INTO `t_tokens` VALUES (15, 8, '088f1f28-a0e0-407a-b5c8-8e96b82773bd', 1, '2020-03-15 18:40:04', '2020-02-14 18:40:04');
INSERT INTO `t_tokens` VALUES (16, 8, '8767dd7d-270a-4562-9c1f-c5a40d6181b8', 1, '2020-03-15 18:40:05', '2020-02-14 18:40:05');
INSERT INTO `t_tokens` VALUES (17, 8, '96ac6555-cfd6-40ff-b86b-7bef637901d3', 1, '2020-03-18 14:49:11', '2020-02-17 14:49:11');
INSERT INTO `t_tokens` VALUES (18, 8, 'd87916ec-b0c6-4417-afba-12d57d620357', 1, '2020-03-20 11:19:31', '2020-02-19 11:19:31');
INSERT INTO `t_tokens` VALUES (19, 9, '5826dac6-8243-4651-a31c-3ea411a8380a', 1, '2020-03-22 15:47:40', '2020-02-21 15:47:40');
INSERT INTO `t_tokens` VALUES (20, 9, '8308d8a8-4509-4217-88b4-8b1ccf2619e2', 1, '2020-03-22 15:48:29', '2020-02-21 15:48:29');
INSERT INTO `t_tokens` VALUES (21, 9, '0be1aa5e-5c4a-4bfa-b2d1-f50c81fab55d', 1, '2020-03-22 15:56:48', '2020-02-21 15:56:48');
INSERT INTO `t_tokens` VALUES (22, 9, 'a630cf01-edcc-4a25-bcbc-6fcd6a4989f4', 1, '2020-03-22 16:06:56', '2020-02-21 16:06:56');
INSERT INTO `t_tokens` VALUES (23, 9, '1158c96c-2438-4e71-ae61-935c1f1d147a', 1, '2020-03-22 16:07:04', '2020-02-21 16:07:04');
INSERT INTO `t_tokens` VALUES (24, 9, 'b57cef74-0bab-4769-abb9-9345a93bd5a8', 1, '2020-03-22 16:55:50', '2020-02-21 16:55:50');
INSERT INTO `t_tokens` VALUES (25, 1, '38f8bed1-b88c-482f-a9b3-c39bf3f31e65', 1, '2020-03-22 19:13:00', '2020-02-21 19:13:00');
COMMIT;

-- ----------------------------
-- Table structure for t_users
-- ----------------------------
DROP TABLE IF EXISTS `t_users`;
CREATE TABLE `t_users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  `password` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '盐',
  `avatar` varchar(5000) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '头像图片',
  `nickname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `sign` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `oauthType` varchar(50) DEFAULT NULL COMMENT 'oauth平台',
  `unionid` varchar(255) DEFAULT NULL,
  `type` tinyint(4) NOT NULL DEFAULT '100' COMMENT '1管理员；100 普通',
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1 正常， 0禁用',
  `createdAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

-- ----------------------------
-- Records of t_users
-- ----------------------------
BEGIN;
INSERT INTO `t_users` VALUES (1, NULL, NULL, NULL, 'https://avatars0.githubusercontent.com/u/11366654?v=4', '蓝月萧枫', 'lanyueos@qq.com', '', 'github', '11366654', 100, 1, '2020-02-14 12:47:32', '2020-02-14 12:47:32');
INSERT INTO `t_users` VALUES (8, 'lanyue', '68940e6be765aecef4b76de735d5c7f8', '86abc2d06953cf1c6d83b6c50a260bc877fcdb99e2fd85b717ff794572ed43af241a214b49eea64573dbbb4513f293660cc9c1da9a0020f54415ed4a320218f5', 'https://avatar-static.segmentfault.com/354/609/3546098233-5d511491a53b9_big64', '管理员', '1752295326@qq.com', '', NULL, NULL, 100, 1, '2020-02-14 18:39:28', '2020-02-14 18:39:28');
INSERT INTO `t_users` VALUES (9, 'admin', '3840aa53f199141ea0922131ed47c379', 'bef1b15259e6b638105b2287f9ac0bd0836d589461e0778a00305d0ef6b3e641b465c6b9955eda983ec6d128fa7b65128fdb3747ab97f434c8804bf9cd88f0f1', 'https://avatar-static.segmentfault.com/354/609/3546098233-5d511491a53b9_big64', '管理员', 'lanyueos@qq.com', '', NULL, NULL, 100, 1, '2020-02-21 15:43:00', '2020-02-21 15:43:00');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
